/*
	Copyright (c) 2010 <copyright holders>
	This source code is licensed under The MIT License,
	see the file LICENSE for details.
	*/

#ifndef CONNECTION_HPP
#define CONNECTION_HPP

#include <boost/asio.hpp>
#include <boost/shared_array.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <list>

#include "ForwardDecls.hpp"
#include "HelpDefs.hpp"
#include "NetDefs.hpp"
#include "gen/netmsg.pb.h"
#include "MessageRegisters.hpp"

namespace spelprog2 {
namespace net {

typedef boost::asio::io_service Service;

struct Connection : public boost::enable_shared_from_this<Connection> {
    typedef boost::asio::ip::tcp::socket Socket;
    typedef boost::shared_ptr<Connection> Pointer;

    static Pointer create(Service & service, Net * net,
        MessageListenerRegistry<NetMessageInfo> & listener)
    {
        return Pointer(new Connection(service, net, listener));
    }
    Socket & getSocket() { return sock; }

    void sendMessage(const Message & msg);
    spelprog2::MessagePtr getMessage();
    bool hasMessage() const { return !msgQueue.empty(); }
    void start(UserId thePeerId);
private:
    HIDE_EVIL_CONSTRUCTORS(Connection);

    typedef boost::array<google::protobuf::uint8, MAX_MESSAGE_BODY_LEN> InBuffer;
    typedef google::protobuf::uint8 OutBufferType;
    typedef boost::shared_array<OutBufferType> OutBufferPtr;
    typedef google::protobuf::io::CodedInputStream Istream;
    typedef google::protobuf::io::CodedOutputStream Ostream;

    Socket sock;
    Net * net_;
    MessageListenerRegistry<NetMessageInfo> & listener_;
    InBuffer recvBuffer;
    std::list<spelprog2::MessagePtr> msgQueue;
    UserId userId;

    explicit Connection(Service & service, Net * net, MessageListenerRegistry<NetMessageInfo> & listeners) :
        sock(service), net_(net), listener_(listeners), recvBuffer(), msgQueue(), userId(-1) {}

    void startHeaderRead();
    void handleHeaderRead(const boost::system::error_code & err);
    void startBodyRead(size_t bodyLen);
    void handleBodyRead(const boost::system::error_code & err);
    void handleWrite(OutBufferPtr buf);
};

}; //namespace net
}; //namespace spelprog2

#endif //CONNECTION_HPP
